Infomormações Gerais

Os dados coletados são referentes ao dataset disponibilizado no kagle por Rubens Junior (https://www.kaggle.com/rubenssjr/brasilian-houses-to-rent), possuem informações retiradas através de Webcrawler em diversos sites com ofertas de alugueis de imoveis. Os dados contém 10962 observações e 13 vaariaveis. Possuem as seguintes colunas:

city= Cidade; area= Tamanho da casa em m2; rooms= Número de quartos; Bathroom= Número de banheiros; Parking spaces= Número de vagas em estacionamento; Floor= Número de andar; Animal= Se aceita animais ou não; Furniture= Se o local é mobiliado ou não; Hoa= Valor do condominio; rent amount (R\()= Valor do aluguel; property tax (R\))= IPTU da casa; fire insurance (R$)= Seguro de incendio da casa; Total= Total pago ao mês pela casa;

Objetivo:

Esse trabalho terá como objetivo prever valores futuros de aluguel utilizando regressão linear

#install.packages("readr")
#install.packages("plotly")
library(readr)
library(visdat)
library(dplyr)
library(ggplot2)
library(plotly)
library(dplyr)
library(corrplot)
library(randomForest)
library(caret)
df<- read_csv("houses_to_rent_v2.csv")
## Parsed with column specification:
## cols(
##   city = col_character(),
##   area = col_double(),
##   rooms = col_double(),
##   bathroom = col_double(),
##   `parking spaces` = col_double(),
##   floor = col_character(),
##   animal = col_character(),
##   furniture = col_character(),
##   `hoa (R$)` = col_double(),
##   `rent amount (R$)` = col_double(),
##   `property tax (R$)` = col_double(),
##   `fire insurance (R$)` = col_double(),
##   `total (R$)` = col_double()
## )
head(df)
## # A tibble: 6 x 13
##   city   area rooms bathroom `parking spaces` floor animal furniture `hoa (R$)`
##   <chr> <dbl> <dbl>    <dbl>            <dbl> <chr> <chr>  <chr>          <dbl>
## 1 São ~    70     2        1                1 7     acept  furnished       2065
## 2 São ~   320     4        4                0 20    acept  not furn~       1200
## 3 Port~    80     1        1                1 6     acept  not furn~       1000
## 4 Port~    51     2        1                0 2     acept  not furn~        270
## 5 São ~    25     1        1                0 1     not a~ not furn~          0
## 6 São ~   376     3        3                7 -     acept  not furn~          0
## # ... with 4 more variables: `rent amount (R$)` <dbl>, `property tax
## #   (R$)` <dbl>, `fire insurance (R$)` <dbl>, `total (R$)` <dbl>

Mudança de nomes de variaveis

Com o objetivo de deixar mais simples a manipulação dos dados e o entendimento, decidimos mudar o nome das variaveis.

names(df)= c("cidade","area","quartos","banheiros","n_estacionamento", "andar","animal","Furniture","condominio","valor_aluguel","IPTU","taxa_incendio","total_pago")
head(df)
## # A tibble: 6 x 13
##   cidade  area quartos banheiros n_estacionamento andar animal Furniture
##   <chr>  <dbl>   <dbl>     <dbl>            <dbl> <chr> <chr>  <chr>    
## 1 São P~    70       2         1                1 7     acept  furnished
## 2 São P~   320       4         4                0 20    acept  not furn~
## 3 Porto~    80       1         1                1 6     acept  not furn~
## 4 Porto~    51       2         1                0 2     acept  not furn~
## 5 São P~    25       1         1                0 1     not a~ not furn~
## 6 São P~   376       3         3                7 -     acept  not furn~
## # ... with 5 more variables: condominio <dbl>, valor_aluguel <dbl>, IPTU <dbl>,
## #   taxa_incendio <dbl>, total_pago <dbl>

Tratando Dados

Inicialmente iremos avaliar se o dataset possuem algum valor faltante.Abaixo é possível perceber que não possuimos nenhum dado faltante, não precisando fazer qualquer tipo de tratamento.

colSums(is.na(df))
##           cidade             area          quartos        banheiros 
##                0                0                0                0 
## n_estacionamento            andar           animal        Furniture 
##                0                0                0                0 
##       condominio    valor_aluguel             IPTU    taxa_incendio 
##                0                0                0                0 
##       total_pago 
##                0

Para começarmos a fazer qualquer tipo de analise, precisamos antes de tudo validar se as variaveis do nosso dataset estão formatadas com tipo de dados certo. Para ficar visualmente mais atrativo, decidimos utilizar o pacote visdat.

vis_dat(df)

Precisamos mudar os tipos das variaveis cidade, animal e furniture para o tipo fator. Embora realmente esses dados sejam strigs, elas representam uma variavel de classificação.

df$cidade= as.factor(df$cidade)
df$animal= as.factor(df$animal)
df$Furniture= as.factor(df$Furniture)
df$banheiros=as.integer(df$banheiros)
df
## # A tibble: 10,692 x 13
##    cidade  area quartos banheiros n_estacionamento andar animal Furniture
##    <fct>  <dbl>   <dbl>     <int>            <dbl> <chr> <fct>  <fct>    
##  1 São P~    70       2         1                1 7     acept  furnished
##  2 São P~   320       4         4                0 20    acept  not furn~
##  3 Porto~    80       1         1                1 6     acept  not furn~
##  4 Porto~    51       2         1                0 2     acept  not furn~
##  5 São P~    25       1         1                0 1     not a~ not furn~
##  6 São P~   376       3         3                7 -     acept  not furn~
##  7 Rio d~    72       2         1                0 7     acept  not furn~
##  8 São P~   213       4         4                4 4     acept  not furn~
##  9 São P~   152       2         2                1 3     acept  furnished
## 10 Rio d~    35       1         1                0 2     acept  furnished
## # ... with 10,682 more rows, and 5 more variables: condominio <dbl>,
## #   valor_aluguel <dbl>, IPTU <dbl>, taxa_incendio <dbl>, total_pago <dbl>
vis_dat(df)

Analise Exploratoria

Com o gráfico abaixo é possível notar que a maioria das casas no dataset são da cidade de São Paulo

g=ggplot(data=df, aes(x=cidade)) + geom_bar(fill="lightblue",)+ coord_flip()+
  theme_classic() + labs(title = "Número de casas para alugar por cidades") + ylab("numero de casas")
ggplotly(g)

Analisando agora os valores pagos em alugueis que é a variável que desejamos prever.Abaixo segue algumas analises estatisticas referentes a variavel valor do aluguel agrupadas por cidade

aggregate(df[,"valor_aluguel"], list(local=df$cidade), mean)
##            local valor_aluguel
## 1 Belo Horizonte      3664.128
## 2       Campinas      2364.291
## 3   Porto Alegre      2337.700
## 4 Rio de Janeiro      3232.904
## 5      São Paulo      4652.794
aggregate(df[,"valor_aluguel"], list(local=df$cidade), sd)
##            local valor_aluguel
## 1 Belo Horizonte      3493.665
## 2       Campinas      2310.903
## 3   Porto Alegre      2199.696
## 4 Rio de Janeiro      2804.266
## 5      São Paulo      3634.612
aggregate(df[,"valor_aluguel"], list(local=df$cidade), max)
##            local valor_aluguel
## 1 Belo Horizonte         15000
## 2       Campinas         15000
## 3   Porto Alegre         19000
## 4 Rio de Janeiro         15000
## 5      São Paulo         45000
aggregate(df[,"valor_aluguel"], list(local=df$cidade), min)
##            local valor_aluguel
## 1 Belo Horizonte           450
## 2       Campinas           500
## 3   Porto Alegre           500
## 4 Rio de Janeiro           500
## 5      São Paulo           500
aggregate(df[,"valor_aluguel"], list(local=df$cidade), median)
##            local valor_aluguel
## 1 Belo Horizonte          2300
## 2       Campinas          1500
## 3   Porto Alegre          1650
## 4 Rio de Janeiro          2300
## 5      São Paulo          3400

Iremos avaliar agora como andam os valores outilines, é possivel já notar pelo desvio padrão que possuimos um conjunto de dados bastante esparço em relação a variavel valor_aluguel.Agora iremos visualizar através de um boxplot

lista=c("banheiros","quartos","n_estacionamento")
legenda=c("Valor do aluguel pela quantidade de banheiros",
          "Valor do alguel pela quantidade de quartos",
          "Valor do aluguel pela quantidade de n_estacionamento")
plot.boxes<-function(X,legenda){
  ggplot(df,aes_string(x=X, y="valor_aluguel",group=X))+
      geom_boxplot() + labs(title = legenda)+
    theme_classic()
        
  
}

Map(plot.boxes,lista,legenda)
## $banheiros

## 
## $quartos

## 
## $n_estacionamento

É possivel notar que as 3 variaveis possuem uma correlação com o valor do aluguel e possuem varios outlines.Decidimos não remove-los e deixa-los no modelo preditivo, pois sua remoção poderia criar um modelo que não representaria a realidade.

Finalizando a nossa analise exploratoria, abaixo segue uma gráfico que mostra a correlação entre as variaveis

colnumericas=sapply(df, is.numeric)
correlacao= cor(df[,colnumericas])
corrplot(correlacao, method = "color",addCoef.col =T) 

É possivel notar uma correlação positiva média a forte entre as variaveis taxa de incendio, número de quartos, número de banheiros e número de vagas de estacionamento com a váriavel valor do aluguel. (Outra correlação muito forte é com o total pago, mas essa variavel não ajudará de nada nosso modelo, pois seu valor depende do preço do aluguel)

Feature Select

Agora utilizaremos um modelo randomForest para criar um modelo com o objetivo de avaliar quais as variaveis mais importantes para prever o valor do aluguel

modelo= randomForest(valor_aluguel~.-total_pago,df,ntree=100,nodesize=10,
                     importance=T)
#Plotando nivel de importancia
varImpPlot(modelo)

Com o nível de importancia das variaveis, podemos saber quais variaveis tem o maior impacto para prever a variável valor do aluguel

Criando modelo de regressão linear

Primeiramento separamos o nosso conjunto de dados em um dataset de treino e outro de teste, 70% dos dados serão utilizados para treinar o modelo e 30% para avaliar a eficácia do mesmo.

set.seed(00)
split<- createDataPartition(df$cidade,p=0.7, list=F)
dados_treino= df[split,]
## Warning: The `i` argument of ``[`()` can't be a matrix as of tibble 3.0.0.
## Convert to a vector.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
dados_teste=df[-split,]

Iremos agora criar o modelo de regressão utilizando apenas as variaveis mais importantes encontradas no feacture select.Seram retirados as variáveis Animal e mobilia por não terem uma significancia para nossa previsão.

dados_treino$andar=NULL
dados_teste$andar=NULL
modeloLinear<- train(valor_aluguel~.-total_pago -animal
                     -Furniture,data=dados_treino, method="lm")

Com o modelo criado será utilizado os dados de testes para avaliar a precisão do modelo criado

previsao<- predict(modeloLinear,dados_teste)
#Dataframe com valor real e valor previsto
score= as.data.frame(cbind(dados_teste$valor_aluguel,previsao))
names(score)=c("Valor_real","Valor_previsto")
head(score)
##   Valor_real Valor_previsto
## 1       3300       3198.164
## 2       2800       2700.631
## 3       2300       2418.738
## 4       4370       4207.622
## 5       8000       8564.544
## 6       3000       3048.444

Avaliando modelo

Analisando o modelo criado, conseguimos um R-squared de 0.98 indicando que a reta criada se adaptou bem aos dados apresentados.

summary(modeloLinear)
## 
## Call:
## lm(formula = .outcome ~ ., data = dat)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -4567.0  -191.4     1.4   183.7 10642.6 
## 
## Coefficients:
##                          Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             1.960e+01  2.317e+01   0.846  0.39757    
## cidadeCampinas          1.648e+02  2.706e+01   6.091 1.18e-09 ***
## `cidadePorto Alegre`   -1.589e+02  2.482e+01  -6.404 1.61e-10 ***
## `cidadeRio de Janeiro`  2.930e+02  2.370e+01  12.360  < 2e-16 ***
## `cidadeSão Paulo`       3.375e+02  1.924e+01  17.547  < 2e-16 ***
## area                   -5.530e-02  1.797e-02  -3.077  0.00210 ** 
## quartos                -7.144e+01  7.793e+00  -9.168  < 2e-16 ***
## banheiros               6.536e+01  7.417e+00   8.812  < 2e-16 ***
## n_estacionamento       -3.901e+01  5.534e+00  -7.049 1.96e-12 ***
## condominio              9.597e-04  3.180e-04   3.018  0.00256 ** 
## IPTU                    2.247e-03  1.591e-03   1.412  0.15789    
## taxa_incendio           7.045e+01  1.747e-01 403.381  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 504.7 on 7475 degrees of freedom
## Multiple R-squared:  0.978,  Adjusted R-squared:  0.978 
## F-statistic: 3.024e+04 on 11 and 7475 DF,  p-value: < 2.2e-16

Agora com base nos valores previstos a partir da base de testes, iremos analisar os residuos gerados com base no valor real do aluguel e no valor que o modelo previu.

Avaliando os residuos é possível notar que criamos um bom modelo pelo fato do mesmo seguir uma normal tendendo a zero. Embora possuimos alguns valores que representam os residuos dos pontos fora da curva.

residuo<- function(real,previsto){
  return(previsto-real)
}
residu=as.data.frame(mapply( residuo,score$Valor_real,score$Valor_previsto))
names(residu)="residuo"

ggplot(residu,aes(x=residuo), with=600) +geom_histogram(bins=50)+
  xlim(c(-2500,2500)) + theme_classic() + labs(title = "Resíduos entre valores reais e previstos")

Em seguida foi plotado os valores reais e previstos em um gráfico para visualizar a diferença entre os valores. É possível notar que os valores ficaram bem proximos um dos outros, mostrando que a análise foi bastante eficaz. Foi mostrado apenas os 500 primeiros valores previstos por motivos de melhor visualização.

score$index=c(1:3205)
ggplotly(ggplot(data=score, aes(x=index,y=Valor_real))+ geom_line(color="red") + labs(title = "Valores Previstos e reais") +geom_line(data=score, aes(x=index, y=Valor_previsto)) +theme_classic() + xlim(c(0,500)))